#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "Behavior.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Pseudostate;
class RedefinableElement;
class Region;
class State;
class Vertex;

/// <summary>
/// StateMachine
/// StateMachines can be used to express event-driven behaviors of parts of a
/// system. Behavior is modeled as a traversal of a graph of Vertices interconnected
/// by one or more joined Transition arcs that are triggered by the dispatching of
/// successive Event occurrences. During this traversal, the StateMachine may
/// execute a sequence of Behaviors associated with various elements of the
/// StateMachine.
/// </summary>
class UMLMODEL_EXPORT StateMachine : public Behavior {

public: // Constructors and destructors
    explicit StateMachine(const QString& umlType="uml::StateMachine");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// LCA
    /// The operation LCA(s1,s2) returns the Region that is the least common ancestor of
    /// Vertices s1 and s2, based on the StateMachine containment hierarchy.
    /// </summary>
    virtual shared_ptr<Region> LCA(shared_ptr<Vertex> s1, shared_ptr<Vertex> s2) const;

    /// <summary>
    /// ancestor
    /// The query ancestor(s1, s2) checks whether Vertex s2 is an ancestor of Vertex s1.
    /// </summary>
    virtual bool ancestor(shared_ptr<Vertex> s1, shared_ptr<Vertex> s2) const;

    /// <summary>
    /// isConsistentWith
    /// The query isConsistentWith() specifies that a redefining StateMachine is
    /// consistent with a redefined StateMachine provided that the redefining
    /// StateMachine is an extension of the redefined StateMachine : Regions are
    /// inherited and Regions can be added, inherited Regions can be redefined. In case
    /// of multiple redefining StateMachine, extension implies that the redefining
    /// StateMachine gets orthogonal Regions for each of the redefined StateMachine.
    /// </summary>
    bool isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const override;

    /// <summary>
    /// isRedefinitionContextValid
    /// The query isRedefinitionContextValid() specifies whether the redefinition
    /// context of a StateMachine is properly related to the redefinition contexts of
    /// the specified StateMachine to allow this element to redefine the other. The
    /// context Classifier of a redefining StateMachine must redefine the context
    /// Classifier of the redefined StateMachine.
    /// </summary>
    bool isRedefinitionContextValid(shared_ptr<RedefinableElement> redefinedElement) const override;

    /// <summary>
    /// LCAState
    /// This utility funciton is like the LCA, except that it returns the nearest
    /// composite State that contains both input Vertices.
    /// </summary>
    virtual shared_ptr<State> LCAState(shared_ptr<Vertex> v1, shared_ptr<Vertex> v2) const;

public: // Properties
    /// <summary>
    /// connectionPoints getter
    /// The connection points defined for this StateMachine. They represent the
    /// interface of the StateMachine when used as part of submachine State
    /// </summary>
    vector<shared_ptr<Pseudostate>>& connectionPoints();

    /// <summary>
    /// extendedStateMachines getter
    /// The StateMachines of which this is an extension.
    /// </summary>
    vector<shared_ptr<StateMachine>>& extendedStateMachines();

    /// <summary>
    /// regions getter
    /// The Regions owned directly by the StateMachine.
    /// </summary>
    vector<shared_ptr<Region>>& regions();

    /// <summary>
    /// submachineStates getter
    /// References the submachine(s) in case of a submachine State. Multiple machines
    /// are referenced in case of a concurrent State.
    /// </summary>
    vector<shared_ptr<State>>& submachineStates();

private: // Fields
    /// <summary>
    /// connectionPoints
    /// The connection points defined for this StateMachine. They represent the
    /// interface of the StateMachine when used as part of submachine State
    /// </summary>
    vector<shared_ptr<Pseudostate>> connectionPoints_;

    /// <summary>
    /// extendedStateMachines
    /// The StateMachines of which this is an extension.
    /// </summary>
    vector<shared_ptr<StateMachine>> extendedStateMachines_;

    /// <summary>
    /// regions
    /// The Regions owned directly by the StateMachine.
    /// </summary>
    vector<shared_ptr<Region>> regions_;

    /// <summary>
    /// submachineStates
    /// References the submachine(s) in case of a submachine State. Multiple machines
    /// are referenced in case of a concurrent State.
    /// </summary>
    vector<shared_ptr<State>> submachineStates_;

};

} // namespace uml
